#include "GWindow.h"

#include "GBox.h"
#include "GColor.h"
#include "GLabel.h"
#include "GProgressBar.h"
#include "GText.h"
#include "Object.h"
#include "Tools.h"

#include <math.h>

struct _GWindow
{
        GWidget parent_instance;
        // 主界面 Box
        GWidget *main_box;
        GWidget *title_box;
        GWidget *charge_state_box;
        GWidget *charged_var_box;
        GWidget *state_box;
        GWidget *progress_inner_box;
        GWidget *progress_box;
        GWidget *pv_fixed_box;
        GWidget *pv_variable_box;
        GWidget *money_fixed_box;
        GWidget *money_var_box;
        GWidget *reservation_box;
        GWidget *extra_info_box;
        GWidget *debug_box;
        // 主界面 ProgressBar
        GWidget *progress_bar;
        // 主界面 Label
        GWidget *title_label;
        GWidget *charge_state_var_label;
        GWidget *charged_fixed_label;
        GWidget *charged_time_var_label;
        GWidget *progress_num_var_label;
        GWidget *power_fixed_label;
        GWidget *voltage_fixed_label;
        GWidget *power_var_label;
        GWidget *voltage_var_label;
        GWidget *balance_fixed_label;
        GWidget *price_fixed_label;
        GWidget *balance_var_label;
        GWidget *price_var_label;
        GWidget *reservation_fixed_label;
        GWidget *reservation_var_label;
        GWidget *temp_var_label;
        GWidget *users_var_label;
        GWidget *debug_label;
};

static void
g_window_layout(GWindow *self)
{
        /* 创建对象 */
        self->main_box         = g_box_new(G_ORIENTATION_VERTICAL, true);
        self->title_box        = g_box_new(G_ORIENTATION_VERTICAL, true);
        self->state_box        = g_box_new(G_ORIENTATION_VERTICAL, true);
        self->charge_state_box = g_box_new(G_ORIENTATION_HORIZONTAL, false);
        self->charged_var_box  = g_box_new(G_ORIENTATION_HORIZONTAL, true);
        self->progress_box     = g_box_new(G_ORIENTATION_HORIZONTAL, false);
        self->pv_fixed_box     = g_box_new(G_ORIENTATION_HORIZONTAL, true);
        self->pv_variable_box  = g_box_new(G_ORIENTATION_HORIZONTAL, true);
        self->money_fixed_box  = g_box_new(G_ORIENTATION_HORIZONTAL, true);
        self->money_var_box    = g_box_new(G_ORIENTATION_HORIZONTAL, true);
        self->reservation_box  = g_box_new(G_ORIENTATION_HORIZONTAL, true);
        self->extra_info_box   = g_box_new(G_ORIENTATION_HORIZONTAL, true);
        self->debug_box        = g_box_new(G_ORIENTATION_HORIZONTAL, true);
        self->progress_bar     = g_progress_bar_new(180);
        self->title_label      = g_label_new();
        self->charge_state_var_label  = g_label_new();
        self->charged_fixed_label     = g_label_new();
        self->charged_time_var_label  = g_label_new();
        self->progress_num_var_label  = g_label_new();
        self->power_fixed_label       = g_label_new();
        self->voltage_fixed_label     = g_label_new();
        self->power_var_label         = g_label_new();
        self->voltage_var_label       = g_label_new();
        self->balance_fixed_label     = g_label_new();
        self->price_fixed_label       = g_label_new();
        self->balance_var_label       = g_label_new();
        self->price_var_label         = g_label_new();
        self->reservation_fixed_label = g_label_new();
        self->reservation_var_label   = g_label_new();
        self->temp_var_label          = g_label_new();
        self->users_var_label         = g_label_new();
        self->debug_label             = g_label_new();

        /* 设置小部件属性 */
        g_widget_set_margin(self->main_box, 10);

        g_label_set_text(G_LABEL(self->title_label), g_text_title);
        g_widget_set_align(self->title_label, G_ALIGN_TOP);
        g_label_set_background_color(G_LABEL(self->title_label),
                                     G_COLOR(255, 255, 180));

        g_label_set_text(G_LABEL(self->charge_state_var_label),
                         g_text_fixed_stop_charge);
        g_widget_set_margin(self->charge_state_var_label, 4);
        g_widget_set_align(self->charge_state_var_label, G_ALIGN_BOTTOM);

        g_label_set_text(G_LABEL(self->charged_fixed_label),
                         g_text_fixed_charged);
        g_widget_set_margin(self->charged_fixed_label, 4);
        g_widget_set_align(self->charged_fixed_label,
                           G_ALIGN_BOTTOM | G_ALIGN_RIGHT);

        g_label_set_text(G_LABEL(self->charged_time_var_label),
                         g_text_var_charged_time);
        g_widget_set_margin(self->charged_time_var_label, 4);
        g_widget_set_align(self->charged_time_var_label, G_ALIGN_BOTTOM);

        g_label_set_text(G_LABEL(self->progress_num_var_label),
                         g_text_var_charged_percent);
        g_widget_set_align(self->progress_num_var_label, G_ALIGN_RIGHT);

        g_label_set_text(G_LABEL(self->power_fixed_label), g_text_fixed_power);
        g_widget_set_align(self->power_fixed_label, G_ALIGN_BOTTOM);
        g_widget_set_margin(self->power_fixed_label, 5);
        g_label_set_text(G_LABEL(self->voltage_fixed_label),
                         g_text_fixed_voltage);
        g_widget_set_align(self->voltage_fixed_label, G_ALIGN_BOTTOM);
        g_widget_set_margin(self->voltage_fixed_label, 5);

        g_label_set_text(G_LABEL(self->power_var_label), g_text_var_power);
        g_widget_set_align(self->power_var_label, G_ALIGN_TOP);
        g_widget_set_margin(self->power_var_label, 5);
        g_label_set_text(G_LABEL(self->voltage_var_label), g_text_var_voltage);
        g_widget_set_align(self->voltage_var_label, G_ALIGN_TOP);
        g_widget_set_margin(self->voltage_var_label, 5);

        g_label_set_text(G_LABEL(self->balance_fixed_label),
                         g_text_fixed_balance);
        g_widget_set_align(self->balance_fixed_label, G_ALIGN_BOTTOM);
        g_widget_set_margin(self->balance_fixed_label, 5);
        g_label_set_text(G_LABEL(self->price_fixed_label), g_text_fixed_price);
        g_widget_set_align(self->price_fixed_label, G_ALIGN_BOTTOM);
        g_widget_set_margin(self->price_fixed_label, 5);

        g_label_set_text(G_LABEL(self->balance_var_label), g_text_var_balance);
        g_widget_set_align(self->balance_var_label, G_ALIGN_TOP);
        g_widget_set_margin(self->balance_var_label, 5);
        g_label_set_text_color(G_LABEL(self->balance_var_label),
                               G_COLOR(200, 200, 0));
        g_label_set_text(G_LABEL(self->price_var_label), g_text_var_price);
        g_widget_set_align(self->price_var_label, G_ALIGN_TOP);
        g_widget_set_margin(self->price_var_label, 5);
        g_label_set_text_color(G_LABEL(self->price_var_label),
                               G_COLOR(255, 100, 0));

        g_label_set_text(G_LABEL(self->reservation_fixed_label),
                         g_text_fixed_reservation);
        g_widget_set_align(self->reservation_fixed_label, G_ALIGN_BOTTOM);
        g_widget_set_margin(self->reservation_fixed_label, 5);
        g_label_set_text(G_LABEL(self->reservation_var_label),
                         g_text_var_reservation);
        g_widget_set_align(self->reservation_var_label, G_ALIGN_TOP);
        g_widget_set_margin(self->reservation_var_label, 5);

        g_label_set_text(G_LABEL(self->temp_var_label), g_text_var_temperature);
        g_widget_set_align(self->temp_var_label, G_ALIGN_BOTTOM);
        g_widget_set_margin(self->temp_var_label, 5);

        g_widget_set_align(self->users_var_label, G_ALIGN_TOP);
        g_widget_set_margin(self->users_var_label, 5);

        g_label_set_text(G_LABEL(self->debug_label), "No debug info");

        // g_widget_set_margin(self->progress_bar, 9);
        g_progress_bar_set_percent(G_PROGRESS_BAR(self->progress_bar), 0.0f);

        /* 设置包含关系 */
        g_box_append(G_BOX(self->title_box), self->title_label);
        g_box_append(G_BOX(self->main_box), self->title_box);

        g_box_append(G_BOX(self->charged_var_box), self->charged_fixed_label);
        g_box_append(G_BOX(self->charged_var_box),
                     self->charged_time_var_label);
        g_box_append(G_BOX(self->charge_state_box),
                     self->charge_state_var_label);
        g_box_append(G_BOX(self->charge_state_box), self->charged_var_box);
        g_box_append(G_BOX(self->state_box), self->charge_state_box);

        g_box_append(G_BOX(self->progress_box), self->progress_bar);
        g_box_append(G_BOX(self->progress_box), self->progress_num_var_label);
        g_box_append(G_BOX(self->state_box), self->progress_box);

        g_box_append(G_BOX(self->main_box), self->state_box);

        g_box_append(G_BOX(self->pv_fixed_box), self->power_fixed_label);
        g_box_append(G_BOX(self->pv_fixed_box), self->voltage_fixed_label);
        g_box_append(G_BOX(self->main_box), self->pv_fixed_box);

        g_box_append(G_BOX(self->pv_variable_box), self->power_var_label);
        g_box_append(G_BOX(self->pv_variable_box), self->voltage_var_label);
        g_box_append(G_BOX(self->main_box), self->pv_variable_box);

        g_box_append(G_BOX(self->money_fixed_box), self->balance_fixed_label);
        g_box_append(G_BOX(self->money_fixed_box), self->price_fixed_label);
        g_box_append(G_BOX(self->main_box), self->money_fixed_box);

        g_box_append(G_BOX(self->money_var_box), self->balance_var_label);
        g_box_append(G_BOX(self->money_var_box), self->price_var_label);
        g_box_append(G_BOX(self->main_box), self->money_var_box);

        g_box_append(G_BOX(self->reservation_box),
                     self->reservation_fixed_label);
        g_box_append(G_BOX(self->reservation_box), self->temp_var_label);
        g_box_append(G_BOX(self->main_box), self->reservation_box);

        g_box_append(G_BOX(self->extra_info_box), self->reservation_var_label);
        g_box_append(G_BOX(self->extra_info_box), self->users_var_label);
        g_box_append(G_BOX(self->main_box), self->extra_info_box);

        //g_box_append(G_BOX(self->debug_box), self->debug_label);
        //g_box_append(G_BOX(self->main_box), self->debug_box);

        self->main_box->is_update = true;
}

static uint16_t
g_window_get_width(GWindow *self)
{
        return SCREEN_WIDTH;
}

static uint16_t
g_window_get_height(GWindow *self)
{
        return SCREEN_HEIGHT;
}

static void
g_window_render(const GWindow *self,
                const uint16_t startX,
                const uint16_t startY,
                const uint16_t endX,
                const uint16_t endY)
{
        // if (G_WIDGET(self)->force_render)
        // g_widget_set_force_render(G_WIDGET(self->main_box));
        g_widget_render(self->main_box, startX, startY, endX, endY);
}

GWidget *
g_window_new(void)
{
        GWindow *self = object_new(GWindow);
        g_widget_init(G_WIDGET(self),
                      G_WIDGET_NUMS_CALLBACK(g_window_get_width),
                      G_WIDGET_NUMS_CALLBACK(g_window_get_height),
                      G_WIDGET_RENDER(g_window_render));
        g_window_layout(self);
        g_widget_set_force_render(G_WIDGET(self));
        return G_WIDGET(self);
}

void
g_window_set_mode(const GWindow *self, const GModeType mode)
{
        switch (mode) {
        case G_MODE_TYPE_FAST:
                g_label_set_text(G_LABEL(self->charge_state_var_label),
                                 g_text_fixed_fast_charge);
                break;
        case G_MODE_TYPE_SLOW:
                g_label_set_text(G_LABEL(self->charge_state_var_label),
                                 g_text_fixed_slow_charge);
                break;
        case G_MODE_TYPE_AUTO:
                g_label_set_text(G_LABEL(self->charge_state_var_label),
                                 g_text_fixed_auto_charge);
                break;
        case G_MODE_TYPE_HANDLE:
                g_label_set_text(G_LABEL(self->charge_state_var_label),
                                 g_text_fixed_hand_charge);
                break;
        case G_MODE_TYPE_NEED_LOGIN:
                g_label_set_text(G_LABEL(self->charge_state_var_label),
                                 "\245\246\247");
                break;
        default:
                g_label_set_text(G_LABEL(self->charge_state_var_label),
                                 g_text_fixed_stop_charge);
                break;
        }
}

void
g_window_set_temp(const GWindow *self, const float temp[])
{
        static unsigned char temp_compared[] = "00000000000000";
        sprintf_b(g_text_var_temperature, "%.1f/%.1f\x9f", temp[0], temp[1]);
        /* 文字一致时不刷新 Label 部件，减少刷新频率 */
        if (!strcmp_b(temp_compared, g_text_var_temperature)) {
                g_label_set_text(G_LABEL(self->temp_var_label),
                                 g_text_var_temperature);
                strcpy_b(temp_compared, g_text_var_temperature, 8);
        }
}

void
g_window_set_voltage(const GWindow *self, const float voltage)
{
        sprintf_b(g_text_var_voltage, "%.1f V", voltage);
        g_label_set_text(G_LABEL(self->voltage_var_label), g_text_var_voltage);
}

void
g_window_set_power(const GWindow *self, const float power)
{
        if (power <= 1000.0f)
                sprintf_b(g_text_var_power, "%.1f W", power);
        else
                sprintf_b(g_text_var_power, "%.1f kW", power / 1000.0f);
        g_label_set_text(G_LABEL(self->power_var_label), g_text_var_power);
}

void
g_window_set_charge_percent(const GWindow *self, float percent)
{
        g_progress_bar_set_percent(G_PROGRESS_BAR(self->progress_bar), percent);

        percent *= 100.0f;
        const uint32_t percent_int = (uint32_t)percent % 100;
        sprintf_b(g_text_var_charged_percent, "%u%%", percent_int);
        g_label_set_text(G_LABEL(self->progress_num_var_label),
                         g_text_var_charged_percent);
}

void
g_window_set_balance(const GWindow *self, const float balance)
{
        sprintf_b(g_text_var_balance, "%.2f", balance);
        g_label_set_text(G_LABEL(self->balance_var_label), g_text_var_balance);
}

void
g_window_set_users_info(const GWindow *self, const unsigned char *users_info)
{
        g_label_set_text(G_LABEL(self->users_var_label), users_info);
}

void
g_window_set_order_time(const GWindow *self, int8_t order_tm[])
{
        sprintf_b(g_text_var_reservation,
                  "%2d:%2d:%2d",
                  order_tm[0],
                  order_tm[1],
                  order_tm[2]);
        g_label_set_text(G_LABEL(self->reservation_var_label),
                         g_text_var_reservation);
}

void
g_window_set_charging_time(const GWindow *self, uint8_t charged_tm[])
{
        sprintf_b(g_text_var_charged_time,
                  "%2u:%2u:%2u",
                  charged_tm[0],
                  charged_tm[1],
                  charged_tm[2]);
        g_label_set_text(G_LABEL(self->charged_time_var_label),
                         g_text_var_charged_time);
}

void
g_window_set_charge_process(const GWindow *self, const float percent)
{
        static float _percent = -1.0f;
        if (percent < _percent) {
                g_progress_bar_reset(G_PROGRESS_BAR(self->progress_bar));
                _percent = percent;
        }
        g_progress_bar_set_percent(G_PROGRESS_BAR(self->progress_bar), percent);
        sprintf_b(g_text_var_charged_percent,
                  "%u%%",
                  (uint16_t)(percent * 100) % 101);
        g_label_set_text(G_LABEL(self->progress_num_var_label),
                         g_text_var_charged_percent);
        _percent = percent;
}

void
g_window_set_charge_mode(const GWindow *self, const ChargeMode mode)
{
        static ChargeMode _mode = 1;
        if (_mode == mode)
                return;
        switch (mode) {
        case CHARGE_MODE_AUTO:
                g_window_set_mode(self, G_MODE_TYPE_AUTO);
                break;
        case CHARGE_MODE_FAST:
                g_window_set_mode(self, G_MODE_TYPE_FAST);
                break;
        case CHARGE_MODE_HAND:
                g_window_set_mode(self, G_MODE_TYPE_HANDLE);
                break;
        case CHARGE_MODE_SLOW:
                g_window_set_mode(self, G_MODE_TYPE_SLOW);
                break;
        case CHARGE_MODE_NONE:
                g_window_set_mode(self, G_MODE_TYPE_NONE);
                break;
        }
        _mode = mode;
}

void
g_window_set_price(const GWindow *self, float price)
{
        static float _price = 0.0f;
        if (_price == price)
                return;
        _price = price;
        sprintf_b(g_text_var_price, "%.2f/kWh", _price);
        g_label_set_text(G_LABEL(self->price_var_label), g_text_var_price);
}

void
g_window_set_debug_info(const GWindow *self, const unsigned char *debug_info)
{
        g_label_set_text(G_LABEL(self->debug_label), debug_info);
}
